package com.ruoyi.quartz.service.impl;

import com.ruoyi.bus.domain.*;
import com.ruoyi.bus.service.*;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.quartz.service.IPlanBusBService;
import com.ruoyi.system.service.ISysConfigService;
import com.ruoyi.system.service.ISysUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * @Description
 * @Author caiyanshan
 * @Date 2021/6/18 9:20
 * @Param
 * @Return
 */
@Slf4j
@Service
public class PlanBusBServiceImpl implements IPlanBusBService {
  
  @Autowired
  private IWitAppointService appointService;
  @Autowired
  private IWitRouteService routeService;
  @Autowired
  private IWitBusService busService;
  @Autowired
  private IWitPlanService planService;
  @Autowired
  private ISysConfigService configService;
  @Autowired
  private ISysUserService userService;
  @Autowired
  private IWitChangeDriverService changeDriverService;

  private static String seatReservation;

  @Transactional
  public void changePlanUser(String driveTimes, Date date){
    WitChangeDriver changeDriver = new WitChangeDriver();
    changeDriver.setDriveTime(driveTimes);
    changeDriver.setGotoTime(date);
    List<WitChangeDriver> changeDriverList = changeDriverService.selectWitChangeDriverList(changeDriver);
    if(changeDriverList.size() == 0){
      log.info("today is not change driver user, do not changePlanUser");
      return;
    }
    for(WitChangeDriver witChangeDriver : changeDriverList){
      String driveTime = witChangeDriver.getDriveTime();
      Date gotoTime = witChangeDriver.getGotoTime();
      WitPlan witPlan = new WitPlan();
      witPlan.setSendTime(gotoTime);
      witPlan.setDriveTime(driveTime);
      witPlan.setRouteId(witChangeDriver.getRouteId());
      List<WitPlan> witPlanList = planService.selectWitPlanList(witPlan);
      if(witPlanList.size() == 0){//没排班，说明这个人今天不用出车
        witChangeDriver.setChangeStatus(2);
        witChangeDriver.setRemark("没有预约用户，该司机无需出车.");
        changeDriverService.updateWitChangeDriver(witChangeDriver);
        continue;
      }
      witPlan = witPlanList.get(0);
      SysUser sysUser = userService.selectUserById(witChangeDriver.getNewUserId());
      WitPlan planTemp = new WitPlan();
      planTemp.setDriverUserId(sysUser.getUserId());
      planTemp.setSendTime(gotoTime);
      planTemp.setDriveTime(driveTime);
      List<WitPlan> witPlans = planService.selectWitPlanList(planTemp);
      if(witPlans.size() != 0){
        witChangeDriver.setChangeStatus(4);
        witChangeDriver.setRemark("新司机已被排班,无法换班");
        changeDriverService.updateWitChangeDriver(witChangeDriver);
        continue;
      }
      if(witChangeDriver.getChangeBus().intValue() == 1){//1为更改车辆信息
        WitBus witBus = new WitBus();
        witBus.setUserId(sysUser.getUserId());
        witBus.setBusStatus(0);
        List<WitBus> witBusList = busService.selectWitBusList(witBus);
        if(witBusList.size() == 0){
          witChangeDriver.setChangeStatus(3);
          witChangeDriver.setRemark("新司机不存在绑定车辆");
          changeDriverService.updateWitChangeDriver(witChangeDriver);
          continue;
        }
        witBus = witBusList.get(0);
        witPlan.setBusId(witBus.getBusId());
        witPlan.setBusModel(witBus.getBusModel());
        witPlan.setBusNumber(witBus.getBusNumber());
      }
      witPlan.setDriverUserId(sysUser.getUserId());
      witPlan.setDriverUserName(sysUser.getUserName());
      planService.updateWitPlan(witPlan);
      witChangeDriver.setUserId(1l);
      witChangeDriver.setUserName("系统管理员");
      witChangeDriver.setRemark("系统自动换班");
      witChangeDriver.setPlanId(witPlan.getPlanId());

      WitAppoint witAppoint = new WitAppoint();
      witAppoint.setDriverUserId(sysUser.getUserId());
      witAppoint.setDriverUserName(sysUser.getUserName());
      witAppoint.setDriverUserPhone(sysUser.getPhonenumber());
      witAppoint.setPlanId(witPlan.getPlanId());

      if(witChangeDriver.getChangeBus().intValue() == 1){//给与预约数据更改
        witAppoint.setBusModel(witPlan.getBusModel());
        witAppoint.setBusId(witPlan.getBusId());
        witAppoint.setBusNumber(witPlan.getBusNumber());
      }

      appointService.updateWitAppointByPlanId(witAppoint);

      changeDriverService.updateWitChangeDriver(witChangeDriver);
    }
  }
  
  @Override
  @Transactional
  public void plan(String driveTimes, Date date) {
    try{
      List<WitAppoint> witAppointList = this.listAppointData(driveTimes, date);
      if(witAppointList.size() == 0){
        log.info("today is not appoint, do not plan");
        return;
      }
      for(WitAppoint witAppoint : witAppointList){
        List<WitRoute> witRouteList = this.listRouteByUserAppoint(witAppoint);
        if(witRouteList.size() == 0){
          log.info("no route used, the appointId is : " + witAppoint.getAppointId());
          this.updateAppointStatusToNoBus(witAppoint);//状态更新为无车辆使用,没有找到路线
          continue;
        }
        this.handlePlan(witRouteList, witAppoint);
      }
    }catch(Exception e){
      log.error("排班"+ driveTimes +"计划执行失败,异常为:" + e);
      throw e;
    }

  }
  
  
  private List<WitAppoint> listAppointData(String driveTime, Date date){
    WitAppoint appoint = new WitAppoint();
    appoint.setAppointStatus(0);//已预约
    appoint.setTempStatus(0);//临时预约不参与排班
    appoint.setGotoTime(date);
    appoint.setDriveTime(driveTime);
    appoint.setIsPlan(2);//未排班过得用户
    return appointService.selectWitAppointList(appoint);
  }
  
  private void handlePlan(List<WitRoute> witRoutes, WitAppoint witAppoint){
    String driveTimes = witAppoint.getDriveTime();
    Date date = witAppoint.getGotoTime();
    WitPlan witPlan = null;
    for(WitRoute route : witRoutes){
      witPlan = new WitPlan();
      Long routeId = route.getRouteId();
      witPlan.setSendTime(date);
      witPlan.setRouteId(routeId);
      witPlan.setDriveTime(driveTimes);
      witPlan.setPlanStatus(0);
      List<WitPlan> witPlanList = planService.selectWitPlanList(witPlan);
      if(witPlanList.size() == 0){//没有排班
        boolean flag = this.createPlan(route, driveTimes, date, witAppoint.getAppointId());
        if(flag){//true 说明有车 成功排班
          return;
        }
      }else{//有排班
        boolean flag = this.updatePlan(witPlanList.get(0), witAppoint.getAppointId());
        if(flag){//true 说明有车 成功排班
          return;
        }
      }
    }
    
    WitAppoint temp = appointService.selectWitAppointById(witAppoint.getAppointId());
    if(temp.getPlanId() == null){
      this.updateAppointStatusToNoBus(witAppoint);
    }
  }
  
  public boolean updatePlan(WitPlan witPlan, Long appointId){
    int seatReservation = this.getSeatReservation();//车座位预留数
    WitBus witBus = busService.selectWitBusById(witPlan.getBusId());
    if(witBus == null){//没有车可以使用
      return false;
    }
    Integer userCount = witPlan.getAppointCount();
    if(userCount >= witBus.getFullLoad() - seatReservation){
      return false;
    }
    witPlan.setAppointCount(witPlan.getAppointCount() + 1);
    planService.updateWitPlan(witPlan);
    this.updateAppointPlan(appointId, witBus, witPlan, getDriverUser(witBus.getUserId()).getPhonenumber());
    return true;
  }
  
  public boolean createPlan(WitRoute route, String driveTimes, Date date, Long appointId){
    WitPlan witPlan = new WitPlan();
    witPlan.setAppointCount(0);//预约数
    WitBus witBus = this.getBus(route.getRouteId(), witPlan);
    if(witBus == null){//没有车可以使用
      return false;
    }
    witPlan.setAppointCount(witPlan.getAppointCount() + 1);
    witPlan.setBusId(witBus.getBusId());
    witPlan.setBusModel(witBus.getBusModel());
    witPlan.setBusNumber(witBus.getBusNumber());
    witPlan.setDriverUserId(witBus.getUserId());
    SysUser user = getDriverUser(witBus.getUserId());
    witPlan.setDriverUserName(user.getUserName());
    witPlan.setDriveTime(driveTimes);
    witPlan.setRouteId(route.getRouteId());
    witPlan.setRouteName(route.getRouteName());
    witPlan.setTempAppointCount(0);
    if(driveTimes.equals("am")){
      witPlan.setSendTime(DateUtils.splicingTime(date, route.getStartAmTime()));//发车时间
    }else {
      witPlan.setSendTime(DateUtils.splicingTime(date, route.getStartPmTime()));//发车时间
    }
    planService.insertWitPlan(witPlan);
    this.updateAppointPlan(appointId, witBus, witPlan, user.getPhonenumber());
    return true;
  }
  
  private void updateAppointStatusToNoBus(WitAppoint witAppoint){
    witAppoint.setAppointStatus(4);
    appointService.updateWitAppoint(witAppoint);
  }
  
  private void updateAppointPlan(Long appointId, WitBus witBus, WitPlan witPlan, String driverUserPhone){
    WitAppoint witAppoint = new WitAppoint();
    witAppoint.setAppointId(appointId);
    witAppoint.setBusId(witBus.getBusId());
    witAppoint.setBusModel(witBus.getBusModel());
    witAppoint.setBusNumber(witBus.getBusNumber());
    witAppoint.setDriverUserId(witPlan.getDriverUserId());
    witAppoint.setDriverUserName(witPlan.getDriverUserName());
    witAppoint.setDriverUserPhone(driverUserPhone);
    witAppoint.setPlanId(witPlan.getPlanId());
    appointService.updateWitAppoint(witAppoint);
  }
  
  private WitBus getBus(Long routeId, WitPlan witPlan){
    int seatReservation = this.getSeatReservation();//车座位预留数
    List<WitBus> witBusList = busService.selectBusByPlanCount(routeId);
    for(WitBus witBus : witBusList){
      if(witPlan != null){
        Integer userCount = witPlan.getAppointCount();
        if(userCount < witBus.getFullLoad() - seatReservation){
          return witBus;
        }
      }else{
        return witBus;
      }
    }
    return null;
  }

  /**
   * @Description 根据预约路线获取用户可执行的路线
   * @Author caiyanshan
   * @Date 2021/6/18 9:45
   * @Param [appoint]
   * @Return java.util.List<com.ruoyi.bus.domain.WitRoute>
   */
  private List<WitRoute> listRouteByUserAppoint(WitAppoint appoint){
    Long endSite = appoint.getEndSiteId();
    if(endSite == null){//没有则取路线终点站
      Long routeId = appoint.getRouteId();
      WitRoute witRoute = routeService.selectWitRouteById(routeId);
      List<WitRouteSite> witRouteSiteList = witRoute.getWitRouteSiteList();
      witRouteSiteList.sort((o1, o2) -> o2.getSort() - o1.getSort());
      WitRouteSite witRouteSite = witRouteSiteList.get(0);
      endSite = witRouteSite.getSiteId();
    }

    Long centerSite = appoint.getSiteId();
    //两个点确定可以行走的路线
    Map<String, Object> paramMap = new HashMap<String, Object>();
    paramMap.put("endSite", endSite);
    paramMap.put("centerSite", centerSite);
    return routeService.selectRouteByTwoSideId(paramMap);//所有可用的路线ID
  }
  
  /**
   * 获取座位预留数
   * @return
   */
  private int getSeatReservation(){

    if(seatReservation == null){
      seatReservation = configService.selectConfigByKey("seat_reservation");
    }

    try{
      return Integer.parseInt(seatReservation);
    }catch (Exception e){
      return 5;//没配置就默认给与5个预留位
    }
  }
  
  private SysUser getDriverUser(Long userId){
    SysUser sysUser = userService.selectUserById(userId);
    if(sysUser != null){
      return sysUser;
    }
    return new SysUser();//可以不设置昵称,但不能报错,防止个人原因删除用户
  }

}
